package se581.banker.listener;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

import org.apache.log4j.Logger;

import se581.banker.BankerConstants;
import se581.banker.service.HealthMonitorService;
import se581.banker.util.ServerSocketInfo;

/**
 * This class check health of the Update Tracker.
 * It uses the ping/echo strategy.
 * It notifies the HealthService if the Tracker is down
 * or slow.
 * 
 * @author mmichalak
 *
 */
public class HealthMonitorListener implements Runnable {
	static Logger logger = Logger.getLogger(HealthMonitorListener.class.getName());
	
	HealthMonitorService healthSvc = null;
	
	ServerSocketInfo serverPort = null;
	
	
	public HealthMonitorListener() {
		super();
	}
	
	public HealthMonitorListener(ServerSocketInfo serverPort) {
		super();
		this.serverPort = serverPort;
	}
		
	
	@Override
	public void run() {
		logger.debug("Starting HealthMonitorListener Thread...");

		Socket clientSocket = null;
		DataOutputStream outToServer = null;
		BufferedReader inFromServer = null;

		String retFromServer;
	  
		int numberOfFailedPings = 0;
		boolean contLoop = true;
		// Ping Update Tracker every n seconds
		while (contLoop) {	
				
			try {
			
							try {
								// Get Socket conn from the HealthService....
								clientSocket = healthSvc.getServerSocket(serverPort);
								
								outToServer =
								     new DataOutputStream(
								     clientSocket.getOutputStream());
								
								inFromServer =
								     new BufferedReader(
								     new InputStreamReader(
								     clientSocket.getInputStream()));
								
								
								outToServer.writeBytes("1 UPDATE -99 0" + '\n');
								retFromServer = inFromServer.readLine();
								logger.debug("SERVER HEARTBEAT RESPONSE: " + serverPort + "  " + retFromServer);
								
								 if ( !(retFromServer != null && retFromServer.startsWith("1 UPDATE") && retFromServer.length() == 14) ) {
									 numberOfFailedPings++;
									 logger.error("--------------> HEALTH SERVICE FAIL for " + serverPort.toString() + " try=" + numberOfFailedPings );
								 }
								 else {
									 numberOfFailedPings = 0; // reset in case of prev failed connections
								 }
									 
							} catch (IOException e) {
								logger.error("ConnectionException:  " +e.getMessage());
								e.printStackTrace();
								numberOfFailedPings++;
							}
							finally {
								try { clientSocket.close(); } catch (IOException e) {
									logger.error("Error closing socket in finally....Oooops, socket leak");
								}
							}
							 
							 if (numberOfFailedPings > 2) {
								 logger.error("Server is unresponsive.  HealthListener is shutting down.  HealthService will be notified.  Server:"  + serverPort.toString());
								 healthSvc.setPingResponse(serverPort); // indicates down
								 //TODO dont break here if want to be able to restart server and work again....
								 contLoop = false;
							 }
							 
		
				Thread.sleep(BankerConstants.UPDATE_HEARTBEAT_INTERVAL * 1000);
				
		 } catch (InterruptedException e) {
			 logger.debug("HealthMonitor Listener interrupted... ");
		 }
							
		}
	}



	public HealthMonitorService getHealthSvc() {
		return healthSvc;
	}



	public void setHealthSvc(HealthMonitorService healthSvc) {
		this.healthSvc = healthSvc;
	}

	public ServerSocketInfo getServerPort() {
		return serverPort;
	}

	public void setServerPort(ServerSocketInfo serverPort) {
		this.serverPort = serverPort;
	}
}
